﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Collections.Concurrent;
using System.Threading;
using System.IO;

namespace 综合同步
{
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public class TCMSRecvPackage_BJ
    {
        public byte header;//帧头0xaa
        public byte dataLength;//数据长度
        public byte subAddress;//从机地址
        public ushort sTrainSpeed;//火车速度m/s
        public ushort sVoltage;//网压
        public ushort sElecitric;//电流
        public ushort sCurrentStationSN;//当前站区号
        public ushort sNextStationSN;//下一区间号
        public ushort sLife;//CCU生命信号
        public byte bData;//开门，关门断电指令。
        public byte uReserv1;//预留
        public byte uReserv2;//预留
        public byte uReserv3;//预留
        public byte uYear;//年
        public byte uMonth;//月
        public byte uDay;//日
        public byte uHour;//时
        public byte uMinute;//分
        public byte uSecond;//秒
        public ushort sReserv4;//预留
        public byte bCRC;//校验
        public byte bTail;//帧尾0x55

        static TcmsData FromPackage(TCMSRecvPackage_BJ packet)
        {
            TcmsData data = new TcmsData();
            byte[] dataBits = null;
            dataBits = BitConverter.GetBytes(packet.sTrainSpeed);
            data.m_fTrainSpeed = (dataBits[0] * 256 + dataBits[1]) * 0.01f * 5 / 18f;//速度
            dataBits = BitConverter.GetBytes(packet.sCurrentStationSN);
            data.m_iCurrentStationSN = dataBits[0] * 256 + dataBits[1];//当前站
            dataBits = BitConverter.GetBytes(packet.sNextStationSN);
            data.m_iNextStationSN = dataBits[0] * 256 + dataBits[1];//下一站

            dataBits = BitConverter.GetBytes(packet.sVoltage);
            data.m_dVoltage = (dataBits[0] * 256 + dataBits[1]);//电压
            dataBits = BitConverter.GetBytes(packet.sElecitric);
            data.m_dElecitric = (dataBits[0] * 256 + dataBits[1]);//电流
            data.m_dElecitric = (data.m_dElecitric > 32768 ? data.m_dElecitric -65535:
                (data.m_dElecitric ==32768?0: data.m_dElecitric));
            dataBits = BitConverter.GetBytes(packet.sLife);
            data.m_uCCUIndex = dataBits[0] * 256 + dataBits[1];//ccu
            data.m_iData = packet.bData;
            data.m_tTime = DateTime.Now;
            return data;
        }
        public static void ParseData(byte[] tcmsBuf, int writeIndex, ref int readIndex, ConcurrentQueue<TcmsData> tcmsPackageQueue)
        {
            int paketlen = Marshal.SizeOf(typeof(TCMSRecvPackage_BJ));
            int datalen = (writeIndex>readIndex?writeIndex-readIndex:tcmsBuf.Length-readIndex+writeIndex);
            while (datalen >= paketlen)
            {
                //170,85
                if (tcmsBuf[readIndex%tcmsBuf.Length] == 0xaa && tcmsBuf[(readIndex + 28)%tcmsBuf.Length] == 0x55)
                {
                    //清零计数
                    byte[] buf = tcmsBuf.Skip(readIndex%tcmsBuf.Length).Take(paketlen).ToArray();
                    buf = buf.Length < paketlen ? buf.Concat(tcmsBuf.Take(paketlen - buf.Length)).ToArray():buf;
                    byte checkCRC = (byte)buf.Skip(2).Take(25).Sum(o => o);
                    TCMSRecvPackage_BJ tcms = ClassByteConvert.CByte2Class<TCMSRecvPackage_BJ>(buf);
                    if (tcms.dataLength == paketlen && tcms.bCRC == checkCRC)
                        //记录当前数据
                        tcmsPackageQueue.Enqueue(FromPackage(tcms));
                    
                    datalen -= paketlen;
                    readIndex += paketlen;
                    readIndex %= tcmsBuf.Length;
                }
                else
                {
                    //FileLogOperator.Info("-------------TCMS解析错误");
                    datalen -= 1;
                    readIndex += 1;
                    readIndex %= tcmsBuf.Length;
                }
            }
        }
        public static void TcmsCommand(ConcurrentQueue<TcmsData> packageQueue)
        {
              //处理接收到的tcms信号
            Task.Run(new Action(() => {
                double poleSpan = 0;
                FTBPoleInfo[] poles=null;
                FixDataBase db = LocalServer.instance().m_db;
                FTBLineInfo line = db.LineInfoEntities.FirstOrDefault();
                int mPoleIndex = 0, mStationIndex=0, mStationNextIndex=0, mDirection=1,mMileage = 1;
                List<FTBStationInfo> stations = db.StationInfoEntities.Where(o=>o.LineID== line.LineID).ToList();
                Dictionary<long, FTBPoleInfo[]> poleDic = db.PoleInfoEntities.ToArray().Join(db.AnchorInfoEntities.ToArray(),
                    o=>o.AnchorID,t=>t.AnchorID,(o,t)=>new {t.StationID,Pole=o}).GroupBy(o=>o.StationID)
                    .ToDictionary(o=>o.Key,t=>t.Select(o=>o.Pole).ToArray());
                while (true)
                {
                    try
                    {
                        if (packageQueue.Count <= 1){
                            Thread.Sleep(1);
                            continue;
                        }
                        #region 站信息
                        TcmsData tcmsLast, tcms;
                        packageQueue.TryDequeue(out tcmsLast);
                        packageQueue.TryPeek(out tcms);
                        //站ID
                        FTBStationInfo[] fTBStation = stations.Where(o=>o.StationNum !=0 && 
                            (o.StationNum == tcms.m_iNextStationSN ||o.StationNum == tcmsLast.m_iNextStationSN)).ToArray();
                        if(fTBStation.Length>1) {
                            mMileage = (fTBStation[0].StationNum == tcms.m_iNextStationSN)?(fTBStation[0].Mileage - fTBStation[1].Mileage):
                                ((fTBStation[1].Mileage - fTBStation[0].Mileage));
                            if(mMileage<0){
                                mDirection = -1*mDirection;
                                line = mDirection>0?db.LineInfoEntities.ToArray().FirstOrDefault():db.LineInfoEntities.ToArray().LastOrDefault();
                                stations = db.StationInfoEntities.Where(o=>o.LineID== line.LineID).ToList();
                                poleDic = db.PoleInfoEntities.ToArray().Join(db.AnchorInfoEntities,
                                    o=>o.AnchorID,t=>t.AnchorID,(o,t)=>new {t.StationID,Pole=o}).GroupBy(o=>o.StationID)
                                    .ToDictionary(o=>o.Key,t=>t.Select(o=>o.Pole).ToArray());
                                FileLogOperator.Error("【"+line.LineName+"】",ConsoleColor.Green);
                            }
                        }
                        mStationNextIndex = stations.ToList().IndexOf(
                            stations.Where(o=>o.StationNum == tcms.m_iNextStationSN).FirstOrDefault());
                        mStationIndex = mStationNextIndex<=0?0:mStationNextIndex-1;
                        //RedisClientBll.sPath = Path.Combine(LocalServer.GetConfigValue<string>("DataPath"),line.LineName);
                        if (tcmsLast.m_iNextStationSN!=tcms.m_iNextStationSN)
                        {//车辆换站
                            PACKAGE_INFO packet = new PACKAGE_INFO() { packtype = (uint)PacketType.StationChange };
                            if(tcmsLast.m_iNextStationSN!=0&&tcms.m_iNextStationSN==0)
                                LocalServer.instance().Section = stations[mStationIndex==0?0:mStationIndex-1].StationName + "-车辆段";
                            else if(tcmsLast.m_iNextStationSN==0&&tcms.m_iNextStationSN!=0)
                                LocalServer.instance().Section = "车辆段-" + stations[mStationIndex+1].StationName;
                            else
                                LocalServer.instance().Section = stations[mStationIndex==0?0:mStationIndex-1].StationName + "-" + stations[mStationIndex+1].StationName;
                            LocalServer.instance().GetServer().SendData(packet.FromPackage(Encoding.Default.GetBytes(LocalServer.instance().Section)));
                            FileLogOperator.Info("车辆换站("+tcmsLast.m_iNextStationSN.ToString("D3")+"-"+tcms.m_iNextStationSN.ToString("D3")+")，"+ LocalServer.instance().Section);
                            if(stations.Count>mStationIndex&&poleDic.ContainsKey(stations[mStationIndex].StationID)){
                                poles = poleDic[stations[mStationIndex].StationID];
                                mPoleIndex = 0;
                            }
                        }
                        #endregion

                        if (packageQueue.Count > 100)
                            FileLogOperator.Info("系统缓存TCMS数据（"+ packageQueue.Count+")");
                        if (tcmsLast.m_iData == 1)
                        {
                            PACKAGE_INFO packet = new PACKAGE_INFO() { packtype = (uint)PacketType.OpenDoor, datalen = 1 };
                            LocalServer.instance().GetServer().SendData(ClassByteConvert.Class2CByte(packet.SetCheckCode()));
                        }
                        else if (tcmsLast.m_iData == 2)
                        {
                            PACKAGE_INFO packet = new PACKAGE_INFO() { packtype = (uint)PacketType.CloseDoor, datalen = 1 };
                            LocalServer.instance().GetServer().SendData(ClassByteConvert.Class2CByte(packet.SetCheckCode()));
                        }
                        else if (tcmsLast.m_iData == 4)
                        {
                            PACKAGE_INFO packet = new PACKAGE_INFO() { packtype = (uint)PacketType.ShutDown, datalen = 1 };
                            LocalServer.instance().GetServer().SendData(ClassByteConvert.Class2CByte(packet.SetCheckCode()));
                        }
                        else
                        {   
                            poleSpan += LocalServer.GetConfigValue<double>("factor") * (tcms.m_tTime - tcmsLast.m_tTime).TotalSeconds * (tcms.m_fTrainSpeed / 2 + tcmsLast.m_fTrainSpeed / 2);
                            if(poles!=null && poles[mPoleIndex].Span<poleSpan*1000){
                                if(mPoleIndex+1<poles.Length) 
                                    mPoleIndex++;
                                poleSpan = 0;
                            }
                            
                            string section;
                            if(tcmsLast.m_iNextStationSN!=0&&tcms.m_iNextStationSN==0)
                                section = stations[mStationIndex==0?0:mStationIndex-1].StationName + "-车辆段";
                            else if(tcmsLast.m_iNextStationSN==0&&tcms.m_iNextStationSN!=0)
                                section = "车辆段-" + stations[mStationIndex+1].StationName;
                            else
                                section = stations[mStationIndex==0?0:mStationIndex-1].StationName + "-" + stations[mStationIndex+1].StationName;

                            PACKAGE_INFO packet = new PACKAGE_INFO() { packtype = (uint)PacketType.RUNNING };
                            string info = line.LineName + ";区间【;" + section+";】;"+stations[mStationIndex==0?0:mStationIndex-1].KmMark + 
                                ";杆号【;"+(poles==null?"":poles[mPoleIndex].PoleName)+";】速度【;"+(tcms.m_fTrainSpeed).ToString("F3") +";m/s】;"+DateTime.Now.ToString("G");
                            LocalServer.instance().GetServer().SendData(packet.FromPackage(Encoding.Default.GetBytes(info)));
                        }
                    }
                    catch (Exception ex) {
                        FileLogOperator.Error("命令错误："+ex.Message);
                    }
                }
            }));
        }
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public class TCMSSendPackage_BJ
    {
        public byte header;//帧头0xaa
        public byte dataLength;//数据长度
        public byte subAddress;//从机地址
        public byte bData1;//第一字节数据
        public byte bData2;//第二字节数据
        public byte bData3;//第三字节数据

        public byte uData1;//预留字节数据
        public byte uData2;//预留字节数据
        public byte uData3;//预留字节数据
        public byte uData4;//预留字节数据
        public byte uData5;//预留字节数据
        public byte uData6;//预留字节数据
        public byte uData7;//预留字节数据
        public byte uData8;//预留字节数据
        public byte uData9;//预留字节数据
        public byte uData10;//预留字节数据
        public byte uData11;//预留字节数据
        public byte uData12;//预留字节数据
        public byte uData13;//预留字节数据

        public byte bCRC;//校验码
        public byte btail;//帧尾
    }
}
